/*
********************************************************************************
* Copyright (C) 2021, xiang.D <dx_65535@163.com>.
* All right reserved.
*
* File Name   : observer.cc
* Author      :
* Version     : V1.0
* Description :
* Journal     : 2021-12-12 init v1.0
* Brief       : Blog: https://blog.csdn.net/qq_38750572?spm=1001.2014.3001.5343
* Others      :
********************************************************************************
*/
#include <iostream>
#include <stdio.h>
#include <list>
#include <string>

using namespace std;

#define OBSERVER_LOGI(fmt, args...) printf("Observer: I: %d " fmt, __LINE__, ##args)
#define OBSERVER_LOGD(fmt, args...) printf("Observer: D: %d " fmt, __LINE__, ##args)
#define OBSERVER_LOGW(fmt, args...) printf("Observer: W: %d " fmt, __LINE__, ##args)
#define OBSERVER_LOGE(fmt, args...) printf("Observer: E: %d " fmt, __LINE__, ##args)
#define OBSERVER_LOG(fmt, args...)  printf(fmt, ##args)

const int MAX_BUF_LEN = 1024;

typedef struct
{
    unsigned int  type;
    char buf[MAX_BUF_LEN];
}SMsgTransfer;

/* 抽象观察者 */
class CObserver
{
public:
    CObserver() {}
    virtual ~CObserver() {}
    virtual int Update(void *pMsg) = 0;
    virtual string GetName() = 0;
};

/* 发布主题抽象接口 */
class CSubject
{
public:
    CSubject() {}

    virtual ~CSubject() {}

    // 注册此事件的观察者
    virtual int Register(CObserver *pObsr) = 0;

    // 从此事件观察者列表清除指定观察者
    virtual int Unregister(CObserver *pObsr) = 0;

    // 向所有观察者发布主题
    virtual int Notify(void *pMsg) = 0;
};

/* 监听无线电的设备: 对讲机 */
class CInterphone : public CObserver
{
public:
    explicit CInterphone(string value)
    {
        mName = value;
    }

    ~CInterphone()
    {

    }

    string GetName()
    {
        return mName;
    }

    int Update(void *pMsg)
    {
        SMsgTransfer *msg = (SMsgTransfer *)pMsg;
        OBSERVER_LOG("%s receive: [0x%x] [%s]\n", mName.c_str(), msg->type, msg->buf);
        return 0;
    }

private:
    string mName;
};

/* 监听无线电的设备: 手机 */
class CPhone : public CObserver
{
public:
    explicit CPhone(string value)
    {
        mName = value;
    }

    ~CPhone()
    {

    }

    string GetName()
    {
        return mName;
    }

    int Update(void *pMsg)
    {
        if (pMsg != NULL)
        {
            SMsgTransfer *msg = (SMsgTransfer *)pMsg;
            OBSERVER_LOG("%s receive: [0x%x] [%s]\n", mName.c_str(), msg->type, msg->buf);
        } else {
            OBSERVER_LOG("%s receive messages cannot be resolved!\n", mName.c_str());
        }

        return 0;
    }

private:
    string mName;
};

/* 无线电发布 */
class CRadio : public CSubject
{
public:
    CRadio()
    {
        mObserverList.clear();
    }

    ~CRadio()
    {

    }

    int Register(CObserver *pObsr)
    {
        if (nullptr != pObsr) {
            mObserverList.push_back(pObsr);
        } else {
            OBSERVER_LOGE("Register failed!\n");
            return -1;
        }

        return 0;
    }

    int Unregister(CObserver *pObsr)
    {
        if (nullptr != pObsr) {
            mObserverList.remove(pObsr);
        } else {
            OBSERVER_LOGE("Unregister failed!\n");
            return -1;
        }

        return 0;
    }

    int Notify(void *pMsg)
    {
        list<CObserver *>::iterator it;
        SMsgTransfer *pGmsg = (SMsgTransfer *)pMsg;

        OBSERVER_LOG("Send radio: [0x%x] [%s]\n", pGmsg->type, pGmsg->buf);
        // loop: 向监听此事件的所有观察者发布主题
        for (it = mObserverList.begin(); it != mObserverList.end(); it++) {
            (*it)->Update(pMsg);
        }

        return 0;
    }

private:
    list <CObserver *> mObserverList;
};

CRadio theRadio;
CPhone thePhoneUser1("Phone user1");
CPhone thePhoneUser2("Phone user2");
CInterphone theInterUser1("Interphone user1");

static int init()
{
    // 注册监听无线电的设备，可放在观察者类初始化内部
    theRadio.Register(&theInterUser1);
    theRadio.Register(&thePhoneUser1);
    theRadio.Register(&thePhoneUser2);

    return 0;
}

int main(int argc, char *argv[])
{
    init();

    // 发出SOS无线电
    OBSERVER_LOG("------------------------------------------\n");
    SMsgTransfer msg1 = {191519, "SOS"};
    theRadio.Notify(&msg1);

    OBSERVER_LOG("------------------------------------------\n");
    SMsgTransfer msg2 = {131313, "HELLO"};
    theRadio.Notify(&msg2);

    return 0;
}
